home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d7 / jmodm308.arc / JMODEM_E.C < prev    next >
Text File  |  1991-01-02  |  19KB  |  300 lines

  1. /****************************************************************************/
  2. /*   FILE JMODEM_E.C                                                        */
  3. /*   Created 11-JAN-1990                 Richard B. Johnson                 */
  4. /*                                       405 Broughton Drive                */
  5. /*                                       Beverly, Massachusetts 01915       */
  6. /*                                       BBS (508) 922-3166                 */
  7. /*   open_chan();                                                           */
  8. /*   close_chan();                                                          */
  9. /*   read_chan();                                                           */
  10. /*   write_chan();                                                          */
  11. /*                      Communications I/O procedures                       */
  12. /*  These procedures will have to be replaced for JMODEM to execute on      */
  13. /*  a system other than a MS_DOS computer. They are VERY hardware-specific. */
  14. /*  These procedures are grouped so that they can be replaced as a unit.    */
  15. /*  You must replace the following:                                         */
  16. /*  (1) OPEN a communications channel.                                      */
  17. /*  (2) CLOSE the opened channel.                                           */
  18. /*  (3) READ [variable] bytes from the channel.                             */
  19. /*  (4) WRITE [variable] bytes to the channel.                              */
  20. /*                                                                          */
  21. /*  When attempting to READ bytes, some sort of time-out must be provided   */
  22. /*  within the routine to prevent a "wait-forever" syndrome.                */
  23. /*                                                                          */
  24. /*  VAX/VMS, QIO routines are ideal!                                        */
  25. /*                                                                          */
  26. /****************************************************************************/
  27. #include <stdio.h>                          /* For FILE structure           */
  28. #include <conio.h>                          /* For _inp() and _outp()       */
  29. #include <dos.h>                            /* For _enable() and _disable() */
  30. #include "jmodem.h"                         /* JMODEM equates               */
  31. #include "uart.h"                           /* 8250 UART equates            */
  32. #if defined (TURBOC)
  33.     #include <mem.h>
  34.     #define  _enable        enable
  35.     #define  _disable       disable
  36.     #define  _dos_setvect   setvect
  37.     #define  _dos_getvect   getvect
  38. #else
  39.     #include <memory.h>                     /* _memcpy();                   */
  40. #endif
  41. /****************************************************************************/
  42. /*                     Structures and templates                             */
  43. /****************************************************************************/
  44. typedef struct  {
  45.         word base;                          /* Base port address            */
  46.         word mask;                          /* Interrupt controller mask    */
  47.         word int_num;                       /* Interrupt number             */
  48.         } PORTS;
  49.  
  50. const PORTS port_pars[] =
  51.                         {
  52.                         {
  53.                         0x3F8   ,           /* Base port address    COM1    */
  54.                         0xEF    ,           /* IRQ4 11101111B       COM1    */
  55.                         0x0C    ,           /* Interrupt number             */
  56.                         }       ,
  57.                         {
  58.                         0x2F8   ,           /* Base port address    COM2    */
  59.                         0xF7    ,           /* IRQ3 11110111B       COM2    */
  60.                         0x0B    ,           /* Interrupt number             */
  61.                         }       ,
  62.                         {
  63.                         0x3E8   ,           /* Base port address    COM3    */
  64.                         0xEF    ,           /* IRQ4 11101111B       COM3    */
  65.                         0x0C    ,           /* Interrupt number             */
  66.                         }       ,
  67.                         {
  68.                         0x2E8   ,           /* Base port address    COM4    */
  69.                         0xF7    ,           /* IRQ3 11110111B       COM4    */
  70.                         0x0B    ,           /* Interrupt number             */
  71.                         }
  72.                         };
  73. /****************************************************************************/
  74. /*                          Global allocation                               */
  75. /****************************************************************************/
  76. byte *write_ptr;                             /* Interrupt buffer            */
  77. byte *read_ptr;                              /* Interrupt buffer            */
  78. word port;                                   /* Port number                 */
  79. word old_mask;                               /* Old interrupt control mask  */
  80. word old_ier;                                /* Old interrupt enable regis  */
  81. word old_stat;                               /* Modem status for flow-contr */
  82. word carrier;                                /* Carrier detect              */
  83. word timer;                                  /* Global timer                */
  84. word hardware_port;                          /* Physical port               */
  85. /****************************************************************************/
  86. /*                        Function prototypes                               */
  87. /****************************************************************************/
  88. void interrupt far fatal_abort(void);        /* Abort vector                */
  89. void interrupt far com_int(void);            /* Interrupt service routine   */
  90. void interrupt far tim_int(void);            /* Timer interrupt             */
  91. void (interrupt far *old_tim)();             /* Pointer to old timer intr.  */
  92. void (interrupt far *old_com)();             /* Pointer to old commu intr.  */
  93. void (interrupt far *old_brk)();             /* Pointer to old break key.   */
  94. /****************************************************************************/
  95. /*                 Open the communications channel                          */
  96. /*                                                                          */
  97. /*    Under MS-DOS this involves saving the com-port vector, interrupt      */
  98. /*    controller mask, and the user-tick timer vector.                      */
  99. /*    New vectors and masks and patched for the communications interrupt    */
  100. /*    service routine and the local timer. These vectors will be restored   */
  101. /*    within the CLOSE channel routine.                                     */
  102. /*                                                                          */
  103. /****************************************************************************/
  104. word open_chan (word user_port)          /* Port offset ( 0-3 )             */
  105. {
  106.     short i;
  107.     user_port--;                         /* Convert to an offset            */
  108.     flush();                             /* Initialize the interrupt buffer */
  109.     hardware_port =
  110.        port_pars[user_port].base;        /* Set hardware port               */
  111.     old_ier  = inp(hardware_port +IER);  /* Get interrupt enable regis      */
  112.     old_brk  = _dos_getvect(0x1B);       /* Get old break key vector        */
  113.     old_mask = inp(0x21);                /* Save old interrupt mask         */
  114.     old_tim  = _dos_getvect(0x1C);       /* Get old DOS timer-tick vector   */
  115.     old_com  = _dos_getvect(
  116.        port_pars[user_port].int_num);    /* Get old communications vector   */
  117.     _dos_setvect(0x1B,fatal_abort);      /* Set fatal abort vector (1)      */
  118.     _dos_setvect(0x23,fatal_abort);      /* Set fatal abort vector (2)      */
  119.     _dos_setvect(0x1C,tim_int);          /* Set new timer interrupt         */
  120.     _dos_setvect(
  121.        port_pars[user_port].int_num,     /* Set new communications vector   */
  122.        com_int);
  123.     outp(0x21,old_mask &
  124.        port_pars[user_port].mask);       /* Set interrupt enable mask       */
  125.     outp(hardware_port+MCR, MOD_ENA);    /* Turn on DTR, RTS, IRQ enable    */
  126.     outp(hardware_port+IER, IER_ERBFI);  /* Enable received data available  */
  127.     for (i=0; i<8; i++)                  /* Edge-triggering, read the ports */
  128.         inp(hardware_port + i);          /* Port to clear                   */
  129.     outp(0x20,0x20);                     /* Reset the hardware controller   */
  130.     timer=9;                             /* 1/2 second wait                 */
  131.     while (timer);                       /* Wait 1/2 second                 */
  132.     flush();                             /* Clear interrupt buffer again    */
  133.     i = inp(hardware_port+MSR);          /* Get current modem status        */
  134.     old_stat = i & MSR_CHK;              /* Get current modem control       */
  135.     carrier  = i & MSR_RLSD;             /* Get any modem carrier           */
  136.     return JM_NRM;
  137. }
  138. /****************************************************************************/
  139. /*                 Close the communications channel                         */
  140. /*                                                                          */
  141. /*    Under MS-DOS this involves restoring the interrupt vectors and        */
  142. /*    controller mask that was saved during the OPEN routine.               */
  143. /*                                                                          */
  144. /****************************************************************************/
  145. word close_chan (word user_port)
  146. {
  147.     outp(hardware_port+IER,old_ier);       /* Set old interrupt enable      */
  148.     outp(0x21,old_mask);                   /* Restore old interrupt mask    */
  149.     _dos_setvect(
  150.        port_pars[user_port].int_num,       /* Set old communications vector */
  151.        old_com);
  152.     _dos_setvect(0x1C,old_tim);            /* Set old timer interrupt       */
  153.     _dos_setvect(0x1B,old_brk);            /* Set old break interrupt       */
  154.     return JM_NRM;
  155. }
  156. /****************************************************************************/
  157. /*              Read from the communications channel                        */
  158. /*                                                                          */
  159. /*    This involves transferring data from the interrupt buffer and         */
  160. /*    maintaining the interrupt buffer pointers. A timeout is established.  */
  161. /*                                                                          */
  162. /****************************************************************************/
  163. word read_chan (word bytes,              /* Bytes requested                 */
  164.                 register byte *buffer)   /* Pointer to user's buffer        */
  165. {
  166.     word count;                          /* Byte count                      */
  167.     word avail;                          /* Bytes available                 */
  168.     timer = TIMOUT;                      /* Set initial timeout value       */
  169.     count = bytes;                       /* Set byte-count                  */
  170.  
  171.     while (count && timer)               /* If byte request or no timeout   */
  172.     {
  173.         avail = write_ptr - read_ptr;    /* Bytes available                 */
  174.         if (avail)                       /* If bytes available              */
  175.         {
  176.             if (avail > count)           /* If more bytes than we need      */
  177.                 avail = count;           /* Take only what we need          */
  178.             memcpy (buffer   ,           /* User's buffer                   */
  179.                     read_ptr ,           /* Interrupt buffer pointer        */
  180.                     avail)   ;           /* Copy to user's buffer           */
  181.             count -= avail;              /* Update count                    */
  182.             read_ptr +=avail;            /* Update read pointer             */
  183.             buffer   +=avail;            /* Update write pointer            */
  184.             timer = TIMOUT;              /* Set new timer value             */
  185.         }
  186.         _disable();                      /* Clear interrupts                */
  187.         if (read_ptr == write_ptr)       /* If no bytes available           */
  188.             read_ptr = write_ptr         /* Initialize the interrupt buffer */
  189.                      = int_buffer;
  190.         _enable();                       /* Enable interrupts               */
  191.     }
  192.     return(bytes - count);               /* Actual characters received      */
  193. }
  194. /****************************************************************************/
  195. /*                      Flush the interrupt buffer                          */
  196. /****************************************************************************/
  197. void flush()
  198. {
  199.     _disable();
  200.     read_ptr = write_ptr = int_buffer;   /* Initialize the interrupt buffer */
  201.     _enable();
  202. }
  203. /****************************************************************************/
  204. /*                      Communications transmit routine                     */
  205. /*    Write 'bytes' bytes from buffer to the UART. Don't return until done  */
  206. /*    unless the carrier failed or the hardware broke.                      */
  207. /****************************************************************************/
  208. word write_chan (word bytes,                  /* Bytes to send              */
  209.                  register byte *buffer)       /* Pointer to the buffer      */
  210. {
  211.     word status;
  212.     byte *sav_sta;
  213.     byte *old_sta;
  214.  
  215.     sav_sta = old_sta = syst.s_sta;           /* Save current status        */
  216.     timer = TIMOUT;
  217.     while ((bytes && timer) && !user_abort )  /* Bytes, no abort, no timout */
  218.     {
  219.         while (
  220.               ( status =                      /* Get modem status           */
  221.               ( inp (hardware_port+MSR)       /* from modem status register */
  222.                 & MSR_CHK )                   /* Check CTS and DSR only     */
  223.               ) != old_stat)                  /* If not the same as before  */
  224.         {                                     /* Flow control loop          */
  225.             if ( (status & MSR_RLSD )         /* ...check modem carrier     */
  226.                  != carrier)                  /* ... if not same as before  */
  227.                 {
  228.                     user_abort = 0x0FFFF;     /* Set the abort flag         */
  229.                     return JM_ABT;            /* ... and get out            */
  230.                 }
  231.             syst.s_sta = flow;                /* Set flow-control status    */
  232.             if ( syst.s_sta != old_sta )      /* If we haven't already      */
  233.             {
  234.                 screen (SCR_FLG,&syst);       /* Show flow-control status   */
  235.             old_sta = syst.s_sta;             /* Flag that we did it        */
  236.             }
  237.         }
  238.     syst.s_sta = sav_sta;                     /* Set previous status        */
  239.     if ( syst.s_sta != old_sta )
  240.         {
  241.             screen (SCR_FLG,&syst);           /* Show previous status       */
  242.         old_sta = syst.s_sta;                 /* Flag that we did it        */
  243.         }
  244.         status = inp(hardware_port+LSR);      /* Get line-status            */
  245.         if (status & LSR_THRE)                /* If TX holding reg empty    */
  246.         {
  247.             outp(hardware_port,*buffer++);    /* Send the byte              */
  248.             bytes--;                          /* Bump the byte-count        */
  249.             timer = TIMOUT;                   /* Set new timer-value        */
  250.         }
  251.     }
  252.     return JM_NRM;
  253. }
  254. /****************************************************************************/
  255. /*                Communications adapter hardware interrupt                 */
  256. /*    This is very simple because we interrupt on receive only. Since we    */
  257. /*    must wait until the entire block has been received and checked be-    */
  258. /*    for doing anything else, the transmitter is polled.                   */
  259. /*                                                                          */
  260. /****************************************************************************/
  261. void interrupt far com_int()
  262. {
  263.     *write_ptr = (byte)
  264.         inp(hardware_port);                    /* Put byte in buffer        */
  265.     outp(0x20,0x20);                           /* Reset hardware controller */
  266.     if (write_ptr < int_buffer + DAT_LEN )     /* Check buffer for overflow */
  267.         write_ptr++;                           /* Bump pointer if room      */
  268. }
  269. /****************************************************************************/
  270. /*                            Timer interrupt                               */
  271. /*    A WORD (timer) gets decremented every timer-tick if it is not already */
  272. /*    zero. This is used to set time-out values in the communication pro-   */
  273. /*    cedures so that a "wait-forever" can't occur.                         */
  274. /*                                                                          */
  275. /****************************************************************************/
  276. void interrupt far tim_int()
  277. {
  278.     if (timer)                             /* If NZ                         */
  279.         timer--;                           /* Bump the timer                */
  280.     outp(0x20,0x20);                       /* Reset the hardware controller */
  281.     _enable();                             /* Allow network interrupts      */
  282. #if !defined (TURBOC)
  283.     _chain_intr(old_tim);                  /* Go to old timer-tick routine  */
  284. #endif
  285. }
  286. /****************************************************************************/
  287. /*                          A B O R T   trap                                */
  288. /*    Control-C and control-break vectors are set to point here so that     */
  289. /*    a user-break harmlessly sets a flag so that interrupt vectors may     */
  290. /*    properly restored upon program exit.                                  */
  291. /*                                                                          */
  292. /****************************************************************************/
  293. void interrupt far fatal_abort()
  294. {
  295.     user_abort = 0xFFFF;                              /* Set abort flag     */
  296.     timer = 0;                                        /* Provoke timout     */
  297. }
  298. /****************************************************************************/
  299. /******************** E N D   O F   M O D U L E *****************************/
  300.